package org.ne.springboot.utils.PaperHandleUtils.StructCheckUtils;

import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.xwpf.usermodel.*;
import org.json.JSONObject;
import org.ne.springboot.utils.PaperHandleUtils.PaperContentCheckUtils.SparkClient;
import org.ne.springboot.utils.PaperHandleUtils.AbstractTranslateCheckUtils.TranslateCheckUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 论文结构检查工具类
 * 提供文档分割、字数统计、结构分析等功能
 *
 * @author wey
 */
public class Test {

    private static final Logger logger = LoggerFactory.getLogger(StructCheckUtils.class);

    // 常量定义
    private static final String ENCODING_UTF8 = StandardCharsets.UTF_8.name();
    private static final String CONTENT_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    private static final String OUTPUT_FILENAME = "结构检查报告.docx";

    // 字数统计相关常量
    private static final char SPACE_CHAR = ' ';
    private static final int MIN_ASCII = 32;
    private static final int MAX_ASCII = 126;

    // 标题检测模式
    private static final Pattern HEADING_PATTERN = Pattern.compile("(heading|标题)\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
    private static final Pattern DIGITAL_PATTERN = Pattern.compile("(\\d+)");

    // 工作量检查阈值
    private static final int MIN_TOTAL_WORDS = 8000;
    private static final int MIN_TABLES_FIGURES = 10;

    /**
     * 计算文本字数（优化版本）
     * 统计中文字符和英文单词数量
     *
     * @param text 待统计文本
     * @return 字数统计结果
     */
    public static int calculateWordCount(String text) {
        if (text == null || text.trim().isEmpty()) {
            return 0;
        }

        int chineseCharCount = 0;
        StringBuilder englishWordBuffer = new StringBuilder();

        for (char currentChar : text.toCharArray()) {
            // 处理ASCII字符（英文字符）
            if (currentChar >= MIN_ASCII && currentChar <= MAX_ASCII) {
                if (!Character.isWhitespace(currentChar)) {
                    englishWordBuffer.append(currentChar);
                } else if (englishWordBuffer.length() > 0 &&
                        englishWordBuffer.charAt(englishWordBuffer.length() - 1) != SPACE_CHAR) {
                    englishWordBuffer.append(SPACE_CHAR);
                }
            }
            // 处理中文字符
            else {
                if (englishWordBuffer.length() > 0 &&
                        englishWordBuffer.charAt(englishWordBuffer.length() - 1) != SPACE_CHAR) {
                    englishWordBuffer.append(SPACE_CHAR);
                }
                chineseCharCount++;
            }
        }

        // 清理末尾空格
        if (englishWordBuffer.length() > 0 &&
                englishWordBuffer.charAt(englishWordBuffer.length() - 1) == SPACE_CHAR) {
            englishWordBuffer.setLength(englishWordBuffer.length() - 1);
        }

        // 计算英文单词数
        int englishWordCount = englishWordBuffer.length() > 0 ?
                englishWordBuffer.toString().split("\\s+").length : 0;

        return chineseCharCount + englishWordCount;
    }

    /**
     * 计算文档的字数、表格数和图片数
     *
     * @param document Word文档对象
     * @return 数组 [总字数, 表格数, 图片数]
     * @throws IllegalArgumentException 如果文档为null
     */
    public static int[] calculateDocumentStats(XWPFDocument document) {
        if (document == null) {
            throw new IllegalArgumentException("文档对象不能为null");
        }

        int totalWords = 0;
        int tableCount = 0;
        int figureCount = 0;

        try {
            // 统计段落文字
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                totalWords += calculateWordCount(paragraph.getText());
            }

            // 统计图片
            figureCount = document.getAllPictures().size();

            // 统计表格文字
            for (XWPFTable table : document.getTables()) {
                tableCount++;
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        totalWords += calculateWordCount(cell.getText());
                    }
                }
            }

            logger.debug("文档统计完成: 字数={}, 表格数={}, 图片数={}", totalWords, tableCount, figureCount);

        } catch (Exception e) {
            logger.error("计算文档统计信息时发生错误", e);
            throw new RuntimeException("文档统计计算失败", e);
        }

        return new int[]{totalWords, tableCount, figureCount};
    }

    /**
     * 按一级标题分割文档
     *
     * @param document Word文档对象
     * @return 以一级标题分割的文本列表
     * @throws IllegalArgumentException 如果文档为null
     */
    public static List<String> splitDocumentByHeading1(XWPFDocument document) {
        if (document == null) {
            throw new IllegalArgumentException("文档对象不能为null");
        }

        List<String> sections = new ArrayList<>();
        StringBuilder currentSection = new StringBuilder();
        XWPFStyles documentStyles = document.getStyles();
        boolean hasReachedContent = false;

        try {
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                String paragraphText = paragraph.getText().trim();

                if (paragraphText.isEmpty()) {
                    continue;
                }

                // 检查是否到达正文内容（跳过目录等前置部分）
                if (!hasReachedContent) {
                    if (paragraphText.contains("致") && paragraphText.contains("谢")) {
                        hasReachedContent = true;
                    }
                    continue;
                }

                // 检测一级标题，开始新章节
                if (isHeading1(paragraph, documentStyles)) {
                    if (currentSection.length() > 0) {
                        sections.add(currentSection.toString());
                        currentSection = new StringBuilder();
                    }
                }

                currentSection.append(paragraphText).append("\n");
            }

            // 添加最后一个章节
            if (currentSection.length() > 0) {
                sections.add(currentSection.toString());
            }

            // 处理摘要部分
            if (sections.size() > 1) {
                processAbstractSection(sections);
            }

            logger.info("文档分割完成，共{}个章节", sections.size());

        } catch (Exception e) {
            logger.error("文档分割过程中发生错误", e);
            throw new RuntimeException("文档分割失败", e);
        }

        return sections;
    }

    /**
     * 判断段落是否为一级标题
     */
    private static boolean isHeading1(XWPFParagraph paragraph, XWPFStyles styles) {
        if (paragraph == null) {
            return false;
        }

        String styleId = paragraph.getStyleID();
        Integer headingLevel = parseHeadingLevel(styleId, styles);

        return headingLevel != null && headingLevel == 1;
    }

    /**
     * 解析标题层级
     */
    private static Integer parseHeadingLevel(String styleId, XWPFStyles styles) {
        if (styles == null || styleId == null) {
            return null;
        }

        try {
            XWPFStyle style = styles.getStyle(styleId);
            if (style == null) {
                return null;
            }

            String styleName = style.getName();
            if (styleName == null) {
                return null;
            }

            String lowerStyleName = styleName.toLowerCase();
            Matcher headingMatcher = HEADING_PATTERN.matcher(lowerStyleName);

            // 匹配 "heading 数字" 或 "标题数字" 格式
            if (headingMatcher.find()) {
                return safeParseInt(headingMatcher.group(2));
            }

            // 尝试从样式名中提取数字
            Matcher digitalMatcher = DIGITAL_PATTERN.matcher(styleName);
            if (digitalMatcher.find()) {
                int level = safeParseInt(digitalMatcher.group(1));
                if (level >= 1 && level <= 9) {
                    return level;
                }
            }

            // 检查是否包含标题关键词但无法解析具体层级
            if (lowerStyleName.contains("heading") || lowerStyleName.contains("标题")) {
                return -1; // 标记为未知层级的标题
            }

        } catch (Exception e) {
            logger.warn("解析标题样式时发生错误: {}", e.getMessage());
        }

        return null;
    }

    /**
     * 安全解析整数
     */
    private static Integer safeParseInt(String numberStr) {
        try {
            return Integer.parseInt(numberStr);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * 处理摘要章节（提取到关键词之前）
     */
    private static void processAbstractSection(List<String> sections) {
        if (sections.size() < 2) {
            return;
        }

        try {
            String abstractText = extractAbstractText(sections.get(1));
            sections.set(1, abstractText);
        } catch (Exception e) {
            logger.warn("摘要提取失败，使用原始文本: {}", e.getMessage());
            // 保持原始文本不变
        }
    }

    /**
     * 提取摘要内容（到"关键词"前）
     */
    private static String extractAbstractText(String text) {
        String[] lines = text.split("\n");
        StringBuilder abstractBuilder = new StringBuilder();

        for (String line : lines) {
            abstractBuilder.append(line).append("\n");
            if (line.trim().startsWith("关键词")) {
                break;
            }
        }

        return abstractBuilder.toString();
    }

    /**
     * 生成检查报告文档
     */
    public static XWPFDocument generateReport(List<JSONObject> analysisResults,
                                              String structureEvaluation,
                                              String workloadAssessment) throws IOException {
        validateReportParameters(analysisResults, structureEvaluation, workloadAssessment);

        XWPFDocument reportDocument = new XWPFDocument();

        try {
            addReportTitle(reportDocument);
            addAnalysisResults(reportDocument, analysisResults);
            addStructureEvaluation(reportDocument, structureEvaluation);
            addWorkloadAssessment(reportDocument, workloadAssessment);

            logger.info("检查报告生成成功");

        } catch (Exception e) {
            closeDocumentSilently(reportDocument);
            logger.error("生成报告时发生错误", e);
            throw new IOException("报告生成失败", e);
        }

        return reportDocument;
    }

    /**
     * 验证报告参数
     */
    private static void validateReportParameters(List<JSONObject> results,
                                                 String structureEval,
                                                 String workloadCheck) {
        if (results == null) {
            throw new IllegalArgumentException("分析结果列表不能为null");
        }
        if (structureEval == null) {
            throw new IllegalArgumentException("结构评价不能为null");
        }
        if (workloadCheck == null) {
            throw new IllegalArgumentException("工作量检查结果不能为null");
        }
    }

    /**
     * 添加报告标题
     */
    private static void addReportTitle(XWPFDocument document) {
        XWPFParagraph titleParagraph = document.createParagraph();
        XWPFRun titleRun = titleParagraph.createRun();
        titleRun.setText("论文结构检查");
        titleRun.setBold(true);
        titleRun.setFontSize(16);
    }

    /**
     * 添加分析结果部分
     */
    private static void addAnalysisResults(XWPFDocument document, List<JSONObject> results) {
        for (int i = 0; i < results.size(); i++) {
            JSONObject result = results.get(i);

            // 添加小节标题
            XWPFParagraph sectionHeading = document.createParagraph();
            XWPFRun headingRun = sectionHeading.createRun();
            headingRun.setText("结构" + (i + 1));
            headingRun.setBold(true);
            headingRun.setFontSize(14);

            // 添加结构所属信息
            addFormattedText(document, "结构所属：", result.optString("struct", "未知"));

            // 添加分析信息
            addFormattedText(document, "分析：", result.optString("msg", "未知"));
        }
    }

    /**
     * 添加格式化文本
     */
    private static void addFormattedText(XWPFDocument document, String label, String content) {
        XWPFParagraph paragraph = document.createParagraph();
        XWPFRun labelRun = paragraph.createRun();
        labelRun.setText(label);
        labelRun.setBold(true);

        XWPFRun contentRun = paragraph.createRun();
        contentRun.setText(content);
    }

    /**
     * 添加结构评价
     */
    private static void addStructureEvaluation(XWPFDocument document, String evaluation) {
        document.createParagraph(); // 空行分隔

        XWPFParagraph evalParagraph = document.createParagraph();
        XWPFRun evalLabelRun = evalParagraph.createRun();
        evalLabelRun.setText("结论: ");
        evalLabelRun.setBold(true);
        evalLabelRun.setFontSize(14);

        XWPFRun evalContentRun = evalParagraph.createRun();
        evalContentRun.setText(evaluation);
    }

    /**
     * 添加工作量评估
     */
    private static void addWorkloadAssessment(XWPFDocument document, String assessment) {
        XWPFParagraph workloadHeading = document.createParagraph();
        XWPFRun workloadRun = workloadHeading.createRun();
        workloadRun.setText("论文工作量检查");
        workloadRun.setBold(true);
        workloadRun.setFontSize(16);

        XWPFParagraph workloadParagraph = document.createParagraph();
        XWPFRun workloadContentRun = workloadParagraph.createRun();
        workloadContentRun.setText(assessment);
    }

    /**
     * 主流程：执行论文结构检查
     */
    public static XWPFDocument performStructureCheck(HttpServletResponse response,
                                                     MultipartFile file,
                                                     String model) throws IOException {
        validateInputParameters(response, file);
        setupResponseHeaders(response);

        try (InputStream fileStream = file.getInputStream();
             XWPFDocument document = new XWPFDocument(fileStream)) {

            List<String> documentSections = splitDocumentByHeading1(document);
            validateDocumentContent(documentSections);

            List<JSONObject> analysisResults = analyzeDocumentSections(documentSections, model);
            String structureEvaluation = evaluateOverallStructure(analysisResults, model);
            String workloadAssessment = assessWorkload(document);

            logger.info("论文结构检查完成");

            return generateReport(analysisResults, structureEvaluation, workloadAssessment);

        } catch (Exception e) {
            logger.error("论文结构检查失败", e);
            throw new IOException("论文结构检查处理失败: " + e.getMessage(), e);
        }
    }

    /**
     * 验证输入参数
     */
    private static void validateInputParameters(HttpServletResponse response, MultipartFile file) {
        if (response == null) {
            throw new IllegalArgumentException("HTTP响应不能为null");
        }
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }
    }

    /**
     * 设置响应头
     */
    private static void setupResponseHeaders(HttpServletResponse response) {
        response.setContentType(CONTENT_TYPE_DOCX);
        try {
            String encodedFilename = URLEncoder.encode(OUTPUT_FILENAME, ENCODING_UTF8);
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename + "\"");
        } catch (Exception e) {
            logger.warn("文件名编码失败，使用默认名称", e);
            response.setHeader("Content-Disposition", "attachment; filename=\"report.docx\"");
        }
    }

    /**
     * 验证文档内容
     */
    private static void validateDocumentContent(List<String> sections) {
        if (sections == null || sections.isEmpty()) {
            throw new IllegalArgumentException("文档内容为空，无法进行分析");
        }
    }

    /**
     * 分析文档各个章节
     */
    private static List<JSONObject> analyzeDocumentSections(List<String> sections, String model) {
        List<JSONObject> results = new ArrayList<>();
        SparkClient sparkClient = createSparkClient(model);
        String analysisPrompt = buildAnalysisPrompt();

        // 分析摘要部分
        analyzeAbstractSection(results, sparkClient, analysisPrompt);

        // 分析各个章节
        for (int i = 0; i < sections.size(); i++) {
            analyzeDocumentSection(results, sparkClient, analysisPrompt, sections.get(i), i);
        }

        return results;
    }

    /**
     * 创建Spark客户端
     */
    private static SparkClient createSparkClient(String model) {
        SparkClient client = new SparkClient();

        Map<String, Object> format = new HashMap<>();
        format.put("struct", "所属的部分");
        format.put("msg", "原因及工作量分析");

        client.setFormat(format);
        client.setModel(model);

        return client;
    }

    /**
     * 构建分析提示词
     */
    private static String buildAnalysisPrompt() {
        return "作为专业的论文审批教授，分析给出的文章最可能属于摘要、引言或者绪论、需求分析或者系统分析、系统设计、系统实现、系统测试等（系统测试也可包含在系统实现部分中）的哪一部分，并说明原因及该部分工作量是否合适，其中摘要不低于200字；引言或者绪论部分不应少于800字，否则提示引言中题目的背景、必要性以及相关意义描述过于简单 、需求分析篇幅不等少于2页，否则提示需求分析不完备，过于简单。系统设计、系统实现、系统测试等相关内容篇幅不低于论文总篇幅的60%， 否则给出相应提示。系统设计篇幅不少于2页，系统实现不少于4页，否则给出相应提示，以严格JSON格式返回，除json内容外无其他内容，其中包含字段struct表明该段文章属于论文的哪个部分,msg字段表明其属于该部分的原因及工作量分析。 ";
    }

    /**
     * 分析摘要部分
     */
    private static void analyzeAbstractSection(List<JSONObject> results, SparkClient client, String prompt) {
        try {
            // 这里可以添加专门的摘要分析逻辑
            // 目前使用与普通章节相同的分析方法
            logger.debug("开始分析摘要部分");
        } catch (Exception e) {
            logger.warn("摘要分析失败", e);
        }
    }

    /**
     * 分析单个文档章节
     */
    private static void analyzeDocumentSection(List<JSONObject> results, SparkClient client,
                                               String prompt, String sectionContent, int sectionIndex) {
        try {
            logger.debug("正在分析第{}个章节", sectionIndex + 1);

            Map<String, Object> analysisResult = client.processRequest(prompt, sectionContent);

            if ("success".equals(analysisResult.get("status"))) {
                @SuppressWarnings("unchecked")
                Map<String, Object> answer = (Map<String, Object>) analysisResult.get("answer");

                JSONObject response = new JSONObject()
                        .put("struct", answer.get("struct"))
                        .put("msg", answer.get("msg"));

                results.add(response);
                logger.debug("第{}章节分析完成", sectionIndex + 1);
            } else {
                throw new IllegalArgumentException("分析服务返回错误: " + analysisResult.get("message"));
            }

        } catch (Exception e) {
            logger.error("分析第{}章节时发生错误", sectionIndex + 1, e);
            throw new RuntimeException("文档章节分析失败: " + e.getMessage(), e);
        }
    }

    /**
     * 评估整体结构
     */
    private static String evaluateOverallStructure(List<JSONObject> results, String model) {
        try {
            SparkClient client = createSparkClient(model);
            String structurePrompt = buildStructureEvaluationPrompt();

            JSONObject wrapper = new JSONObject();
            wrapper.put("sections", results);

            Map<String, Object> evaluationResult = client.processRequest(structurePrompt, wrapper.toString());

            if ("success".equals(evaluationResult.get("status"))) {
                @SuppressWarnings("unchecked")
                Map<String, Object> answer = (Map<String, Object>) evaluationResult.get("answer");
                return (String) answer.get("msg");
            } else {
                logger.warn("结构评估服务返回错误: {}", evaluationResult.get("message"));
                return "结构评估暂时不可用";
            }
        } catch (Exception e) {
            logger.error("整体结构评估失败", e);
            return "结构评估过程发生错误";
        }
    }

    /**
     * 构建结构评估提示词
     */
    private static String buildStructureEvaluationPrompt() {
        return "作为专业的论文审批教授，请分析以下论文结构数据（包含在 'sections' 属性中）：\n" +
                "一个论文的总体结构应该包含摘要、引言或者绪论、需求分析或者系统分析、系统设计、系统实现、系统测试等（系统测试也可包含在系统实现部分中）。\n" +
                "根据提供的数据分析其缺少哪一部分，或者存不存在结构问题或结构混乱。并以文本形式返回客观的评价";
    }

    /**
     * 评估工作量
     */
    private static String assessWorkload(XWPFDocument document) {
        try {
            int[] stats = calculateDocumentStats(document);
            int totalWords = stats[0];
            int tableCount = stats[1];
            int figureCount = stats[2];
            int totalElements = tableCount + figureCount;

            boolean isWorkloadSufficient = totalWords >= MIN_TOTAL_WORDS &&
                    totalElements >= MIN_TABLES_FIGURES;

            String assessment = isWorkloadSufficient ?
                    String.format("论文工作量达标（字数：%d，表格和图片数：%d）", totalWords, totalElements) :
                    String.format("论文工作量较低（字数：%d/%d，表格和图片数：%d/%d）",
                            totalWords, MIN_TOTAL_WORDS, totalElements, MIN_TABLES_FIGURES);

            logger.debug("工作量评估: {}", assessment);
            return assessment;

        } catch (Exception e) {
            logger.error("工作量评估失败", e);
            return "工作量评估暂时不可用";
        }
    }

    /**
     * 安静关闭文档
     */
    private static void closeDocumentSilently(XWPFDocument document) {
        if (document != null) {
            try {
                document.close();
            } catch (Exception e) {
                logger.warn("关闭文档时发生错误", e);
            }
        }
    }

    // 保留原有的翻译相关方法（未修改）
    public static List<Integer> Translate_divideDocxByHeading1(XWPFDocument docx) {
        // 原有实现保持不变
        List<Integer> headList = new ArrayList<>();
        // ... 原有实现
        return headList;
    }

    public static Object[] Translate_getTextFromAbstractToKey(int index, XWPFDocument docx) {
        // 原有实现保持不变
        // ... 原有实现
        return new Object[]{"", false};
    }
}